package com.atguigu.srb.core.service.impl;


import com.alibaba.fastjson.JSON;
import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.srb.base.exception.SrbException;
import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.base.util.SrbAssert;
import com.atguigu.srb.core.config.WxLoginProperties;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.core.service.UserLoginRecordService;
import com.atguigu.srb.core.service.WxLoginService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.ParseException;
import java.util.Map;
import java.util.UUID;

@Service
public class WxLoginServiceImpl implements WxLoginService {

    @Resource
    UserInfoService userInfoService;
    @Resource
    UserLoginRecordService userLoginRecordService;

    @Override
    public String login(HttpSession session) {
        String token = UUID.randomUUID().toString();
        session.setAttribute("token",token);
        return "redirect:"+ WxLoginProperties.API_URL +
                "?appid="+WxLoginProperties.APP_ID +
                "&redirect_uri="+WxLoginProperties.WX_REDIRECT_URI +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state="+token+
                "#wechat_redirect ";
    }

    @Override
    public String callback(String code, String state, HttpSession session, HttpServletRequest request) {
        //校验state值
        Object sessionToken = session.getAttribute("token");
        SrbAssert.AssertNotTrue(StringUtils.isEmpty(state)||sessionToken==null||
                !state.equals(sessionToken), ResponseEnum.WX_LOGIN_CALLBACK_TOKEN_ERROR);
        session.removeAttribute("sessionToken");
        //1、通过code获取access_token
        String path = WxLoginProperties.CALLBACK_URL +
                "?appid="+WxLoginProperties.APP_ID +
                "&secret="+WxLoginProperties.SECRET +
                "&code="+code +
                "&grant_type=authorization_code";
        HttpClientUtils client = new HttpClientUtils(path);
        //发起请求
        UserInfo userInfo = null;
        try {
            client.get();
            //获取响应体中的json字符串
            String result = client.getContent();
            //将响应体结果转为Map
            Map<String, Object> map = JSON.parseObject(result, Map.class);
            //判断相应是否成功
            if (result.contains("errcode")){
                throw new SrbException(map.get("errmsg").toString(),
                        Integer.parseInt(map.get("errcode").toString()));
            }
            //获取code换取的授权凭证token
            String accessToken = map.get("access_token").toString();
            //wx登录授权的wx用户的openid（每个用户wx的openid唯一）
            String openid = map.get("openid").toString();

            userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                    .eq(UserInfo::getOpenid,openid));

            if (userInfo==null){
                //2、使用access_token获取wx用户的个人信息
                map = getWxUserInfo(accessToken, openid);
                //获取用户信息成功
                String nickname = map.get("nickname").toString();
                String headimgurl = map.get("headimgurl").toString();

                //3、根据openid查询wx用户数据如果不存在将wx登录的用户转化为我们自己的用户保存到数据库中
                userInfo = new UserInfo();
                userInfo.setNickName(nickname);
                userInfo.setOpenid(openid);
                userInfo.setHeadImg(headimgurl);
                userInfo.setSalt("wx");
                userInfoService.save(userInfo);
            } else if ((System.currentTimeMillis()-userInfo.getUpdateTime().getTime())>7*24*60*60*1000) {
    //2、使用access_token获取wx用户的个人信息
                path =WxLoginProperties.USERINFO_URL +
                        "?access_token="+accessToken +
                        "&openid="+openid;
                client = new HttpClientUtils(path);
                client.get();
                result = client.getContent();
                map = JSON.parseObject(result, Map.class);
                //判断响应体是否成功
                if (result.contains("errcode")){
                    throw new SrbException(map.get("errmsg").toString(),
                            Integer.parseInt(map.get("errcode").toString()));
                }
                //获取用户信息成功
                String nickname = map.get("nickname").toString();
                String headimgurl = map.get("headimgurl").toString();

                //3、根据openid查询wx用户数据如果不存在将wx登录的用户转化为我们自己的用户保存到数据库中
                userInfo.setNickName(nickname);
                userInfo.setHeadImg(headimgurl);
                userInfoService.updateById(userInfo);

            }
        } catch (Exception e) {
            throw new SrbException(ResponseEnum.WEIXIN_CALLBACK_PARAM_ERROR);
        }

        //保存登录日志
        userLoginRecordService.saveLoginLogs(request,userInfo,2);


        //4、将wx用户的数据展示到登录成功页面（http://localhost:3000）
        //让浏览器重定向访问http://localhost:3000?token=xxx
        String token = JwtUtils.createToken(userInfo.getId(),userInfo.getNickName());
        return "redirect:"+WxLoginProperties.REDIRECT_URL+"?token="+token;
    }

    private static Map<String, Object> getWxUserInfo(String accessToken, String openid) throws IOException, ParseException {
        String result;
        String path;
        Map<String, Object> map;
        HttpClientUtils client;
        path =WxLoginProperties.USERINFO_URL +
                "?access_token="+ accessToken +
                "&openid="+ openid;
        client = new HttpClientUtils(path);
        client.get();
        result = client.getContent();
        map = JSON.parseObject(result, Map.class);
        //判断响应体是否成功
        if (result.contains("errcode")){
            throw new SrbException(map.get("errmsg").toString(),
                    Integer.parseInt(map.get("errcode").toString()));
        }
        return map;
    }
}
